﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Silvermoon.Controls;
using ShoppingList.DTO;
using Silvermoon.UI;
using Silvermoon.Images;
using ShoppingList.Biz;
using Silvermoon.Navigation;
using Silvermoon.Controls.Forms;
using ShoppingList.Utils;
using System.Drawing;
using Silvermoon.Windows.Styles;
using Silvermoon.Shapes;
using Silvermoon.Windows;

namespace ShoppingList.Pages
{
    public class EditListPage : Page
    {
        const string groupLetters = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";

        private ShoppingItem renamingItem;
        private TabControl tabs;
        private ListView availableView, allView, categoryView;
        private TabPage availableTab, allTab, categoryTab;
        private ListViewController<ReverseCheckItem, ShoppingItem> availableController, allController, categoryController;
        private ContextMenu cm;

        public EditListPage()
            : base()
        {
            InitializePage();
        }

        protected override void Dispose(bool dispose)
        {
            DisposeObject(cm);
            base.Dispose(dispose);
        }

        public BizContext Context { get { return BizContext.Context; } }

        private void InitializePage()
        {
            KeepAlive = true;
            Title = "EDIT LIST";
            Styles = StylePool.Main;
            SetTransition(350, TransitionMask.RotateLeftIn, TransitionMask.RotateLeftIn);

            tabs = new TabControl { Margin = Margin.Zero };

            availableView = new ListView { Margin = Margin.Zero };
            allView = new ListView { Margin = Margin.Zero };
            categoryView = new ListView { Margin = Margin.Zero };

            availableTab = new TabPage("available", availableView);
            allTab = new TabPage("all", allView);
            categoryTab = new TabPage("categories", categoryView);
            tabs.SetPages(allTab, availableTab, categoryTab);
            Controls.Add(tabs);

            cm = new ContextMenu();
            cm.AddItem("Rename").Tap += new EventHandler<TapEventArgs>(OnRenameItem);
            cm.AddItem("Delete").Tap += new EventHandler<TapEventArgs>(OnDeleteItem);
            cm.AddItem("Clear shopping list").Tap += new EventHandler<TapEventArgs>(OnClearList);

            availableController = CreateController(availableView);
            allController = CreateController(allView);
            categoryController = CreateCategoryController(categoryView);

            allController.InitializeItem += new EventHandler<ItemControlGeneratorEventArgs<ReverseCheckItem>>(allCt_InitializeItem);
            availableController.InitializeItem += new EventHandler<ItemControlGeneratorEventArgs<ReverseCheckItem>>(availableCt_InitializeItem);
            categoryController.InitializeItem += new EventHandler<ItemControlGeneratorEventArgs<ReverseCheckItem>>(allCt_InitializeItem);

            UpdateData();

            Toolbar tb = new Toolbar();
            tb.AddButton(ImagePool.Save).Tap += new EventHandler<TapEventArgs>(OnOK);
            tb.AddButton(SysImages.Add).Tap += new EventHandler<TapEventArgs>(OnAddArticle);
            tb.AddButton(SysImages.Cancel, Page.BackCommand);
            tb.AddMenuItem("clear shopping list").Tap += new EventHandler<TapEventArgs>(OnClearList);
            Toolbar = tb;
        }

        void OnClearList(object sender, TapEventArgs e)
        {
            cm.UndoAnchor(false);
            foreach (var item in Context.EditList)
            {
                item.IsCompleted = true;
            }
            UpdateData();
        }

        void OnOK(object sender, TapEventArgs e)
        {
            var items = (from i in allController.DataSource where i.IsCompleted == false select i.Name).ToArray();
            if (Context.SetShoppingItems(items))
            {
                GoBack();
            }
        }

        void OnDeleteItem(object sender, TapEventArgs e)
        {
            ShoppingItem item = (cm.AnchorControl as Item).DataValue as ShoppingItem;
            Article p = Context.GetArticle(item.Name);
            if (p != null)
            {
                MessageDialog.Show("Delete article?", p.Name + " will be deleted from your list of articles.", "Delete", "Cancel", () => DeleteArticle(p), null);
            }
        }

        void OnRenameItem(object sender, TapEventArgs e)
        {
            ShoppingItem item = (cm.AnchorControl as Item).DataValue as ShoppingItem;
            Article p = Context.GetArticle(item.Name);
            if (p != null)
            {
                renamingItem = item;
                cm.UndoAnchor(false);
                NewOrEditArticlePage page = new NewOrEditArticlePage(p) { Title = "RENAME ARTICLE" };
                page.Ok += new EventHandler(OnArticleRenamed);
                page.Delete += new EventHandler(OnDelete);
                this.NavigateTo(page, PageTransitions.FromTop);
            }
        }

        void OnAddArticle(object sender, TapEventArgs e)
        {
            Article p = new Article();
            NewOrEditArticlePage page = new NewOrEditArticlePage(p);
            page.Ok += new EventHandler(OnArticleAdded);
            page.Delete += new EventHandler(OnDelete);
            this.NavigateTo(page, PageTransitions.FromTop);
        }

        void OnDelete(object sender, EventArgs e)
        {
            NewOrEditArticlePage page = sender as NewOrEditArticlePage;
            Article p = page.Article;
            DeleteArticle(p);
        }

        private void DeleteArticle(Article p)
        {
            if (Context.DeleteArticle(p))
            {
                cm.UndoAnchor(false);
                ShoppingItem item1 = allController.DataSource.FirstOrDefault(x => string.Equals(p.Name, x.Name, StringComparison.InvariantCultureIgnoreCase));
                if (item1 != null) allController.RemoveValue(item1);
                ShoppingItem item2 = availableController.DataSource.FirstOrDefault(x => string.Equals(p.Name, x.Name, StringComparison.InvariantCultureIgnoreCase));
                if (item2 != null) availableController.RemoveValue(item2);
            }
        }

        void OnArticleAdded(object sender, EventArgs e)
        {
            NewOrEditArticlePage page = sender as NewOrEditArticlePage;
            Article p = page.Article;
            ShoppingItem item = new ShoppingItem(p.Name) { IsCompleted = false };
            if (Context.SaveShoppingItem(item))
            {
                UpdateData();
            }
        }

        void OnArticleRenamed(object sender, EventArgs e)
        {
            NewOrEditArticlePage page = sender as NewOrEditArticlePage;
            Article p = page.Article;
            ShoppingItem item = renamingItem;
            item.Id = -1; // -> make is marked as not new.
            if (Context.SaveShoppingItem(item))
            {
                item.Name = p.Name;
                UpdateData();
            }
            renamingItem = null;
        }

        void availableCt_InitializeItem(object sender, ItemControlGeneratorEventArgs<ReverseCheckItem> e)
        {
            e.Item.ContextMenu = cm;
            e.Item.Tap += new EventHandler<TapEventArgs>(OnAvailableItemTap);
        }

        void allCt_InitializeItem(object sender, ItemControlGeneratorEventArgs<ReverseCheckItem> e)
        {
            e.Item.ContextMenu = cm;
            e.Item.Tap += new EventHandler<TapEventArgs>(OnAllItemTap);
        }

        void OnAllItemTap(object sender, TapEventArgs e)
        {
            var context = Context;
            availableController.DataSource = context.GetAvailableItems();
        }

        void OnAvailableItemTap(object sender, TapEventArgs e)
        {
            ReverseCheckItem item = sender as ReverseCheckItem;
            availableController.RemoveValue(item.DataValue as ShoppingItem);
        }

        private void UpdateData()
        {
            var context = Context;
            availableController.DataSource = context.GetAvailableItems();
            allController.DataSource = context.EditList;
            categoryController.DataSource = context.EditList;
        }

        private ListViewController<ReverseCheckItem, ShoppingItem> CreateController(ListView lv)
        {
            ListViewController<ReverseCheckItem, ShoppingItem> controller = new ListViewController<ReverseCheckItem, ShoppingItem>(lv);
            controller.GetDescriptorFromValue += new EventHandler<GroupDescriptorEventArgs<ShoppingItem>>(GetAzIndexFromValue);
            foreach (char c in groupLetters)
            {
                string s = c.ToString();
                controller.GroupDescriptors.Add(new ItemGroupDescriptor<ShoppingItem>(s));
            }
            controller.ItemHeight = 81;

            return controller;
        }

        private ListViewController<ReverseCheckItem, ShoppingItem> CreateCategoryController(ListView lv)
        {
            ListViewController<ReverseCheckItem, ShoppingItem> controller = new ListViewController<ReverseCheckItem, ShoppingItem>(lv);
            controller.GetDescriptorFromValue += new EventHandler<GroupDescriptorEventArgs<ShoppingItem>>(GetCategoryIndexFromValue);
            SetControllerStyle(controller);
            foreach (var c in Context.Categories)
            {
                controller.GroupDescriptors.Add(new ItemGroupDescriptor<ShoppingItem>(c.Name));
            }
            controller.ItemHeight = 81;

            return controller;
        }

        private void SetControllerStyle(ListViewController<ReverseCheckItem, ShoppingItem> controller)
        {
            controller.PickerTileSize = new Size(400, 80);
            controller.GroupButtonSize = new Size(400, 80);
            controller.GroupPickerStyle = new TextItemStyle
            {
                Padding = Margin.Centered,
                Font = FontPool.BigRegularFont,
            };

            controller.GroupButtonStyle = new ButtonStyle
            {
                StateManager = ButtonStateManagers.BaseManager,
                Margin = Margin.Zero,
                Background = Shape.Empty,
                TextColor = PhoneColors.Accent,
                Font = FontPool.BigRegularFont,
                Padding = new Margin(20, null, null, 8),
                Chrome = Shape.Empty
            };
        }

        void GetCategoryIndexFromValue(object sender, GroupDescriptorEventArgs<ShoppingItem> e)
        {
            var value = e.Value;
            Category c = e.Value.Category;
            int index = c == null ? 0 : Context.Categories.IndexOf(c);
            e.Descriptor = e.GroupDescriptors[index];
        }

        void GetAzIndexFromValue(object sender, GroupDescriptorEventArgs<ShoppingItem> e)
        {
            ShoppingItem data = e.Value;
            string name = data.Name;
            char c = name.Length > 0 ? Char.ToUpper(name[0]) : Char.MinValue;

            int index = groupLetters.IndexOf(c);
            if (index < 0) index = 0;
            e.Descriptor = e.GroupDescriptors[index];
        }
    }
}
